﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Newtonsoft.Json;
using static shbxdv.Ezviz.EZDeviceInfoReponse;
using static shbxdv.Ezviz.EZDeviceListReponse;
using static shbxdv.Ezviz.EzvizOpenSDK;

namespace shbxdv.Ezviz
{
    /// <summary>
    /// 开平SDK
    /// </summary>
    public class EzvizOpenSDK
    {
        private static string ApiUrl = "https://open.ys7.com/api/method";
        //private static string AppKey = "5c8abc7e11c94606b199fb771088c4db";//盘锦大洼；//ConfigurationManager.AppSettings["AppKey"].ToString();//
        private static string AppKey = "23c6c6fa7c974858bbce48cca3ca0d03";//盘锦移动

        private static string AuthAddr = "https://auth.ys7.com";
        //private static string PhoneNumber = "13384271168";//盘锦大洼；//ConfigurationManager.AppSettings["PhoneNumber"].ToString();//
        private static string PhoneNumber = "18516486285";//盘锦移动
        private static string PlatformAddr = "https://open.ys7.com";
        //private static string SecretKey = "d8289da6bec56abc8c7dce10d49af7e7"; //盘锦大洼 ConfigurationManager.AppSettings["SecretKey"].ToString();//
        private static string SecretKey = "f904f8b411d1fab8d76e494345b538be";//盘锦移动

        private static string userId = "1b14cf56-b61d-43f5-a2c8-62b9626cbaaf";//自定义用户名，用guid防止重复

        internal static IDictionary<int, OpenSDKSession> SESSIONS;

        static EzvizOpenSDK()
        {
            SESSIONS = new Dictionary<int, OpenSDKSession>();
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        private EzvizOpenSDK()
        {
        }

        /// <summary>
        /// 初始化SDK
        /// </summary>
        /// <param name="appKey"></param>
        /// <returns>0表示成功，-1表示失败<see cref="OpenSDKErrorCode"/></returns>
        public static int InitSDK(string appKey)
        {
            try
            {
                return OpenNetStream.OpenSDK_Init(appKey);
            }
            catch (Exception)
            {
                return OpenSDKErrorCode.GENERAL_ERROR;
            }
        }

        //初始化库
        public static int InitLibSDK(string appKey)
        {
            try
            {
                return OpenNetStream.OpenSDK_InitLib(AuthAddr, PlatformAddr, appKey);
            }
            catch (Exception)
            {
                return OpenSDKErrorCode.GENERAL_ERROR;
            }

        }

        /// <summary>
        /// 释放SDK
        /// </summary>
        /// <returns>0表示成功，-1表示失败<see cref="OpenSDKErrorCode"/></returns>
        public static int FreeSDK()
        {
            try
            {
                int result = OpenNetStream.OpenSDK_FiniLib();
                if (result == OpenSDKErrorCode.OK)
                    SESSIONS.Clear();
                return result;
            }
            catch (Exception)
            {
                return OpenSDKErrorCode.GENERAL_ERROR;
            }
        }

        /// <summary>
        /// 设置AccessToken
        /// </summary>
        /// <param name="accessToken"></param>
        /// <returns></returns>
        public static int SetAccessToken(string accessToken)
        {
            try
            {
                return OpenNetStream.OpenSDK_SetAccessToken(accessToken);
            }
            catch (Exception)
            {
                return OpenSDKErrorCode.GENERAL_ERROR;
            }

        }

        /// <summary>
        /// 分配会话
        /// </summary>
        /// <returns></returns>
        public static OpenSDKSession AllocSession()
        {
            return AllocSession(IntPtr.Zero);
        }

        /// <summary>
        /// 分配会话
        /// </summary>
        /// <param name="userData"></param>
        /// <returns></returns>
        public static OpenSDKSession AllocSession(IntPtr userData)
        {
            OpenSDKSession openSdkSession = new OpenSDKSession();
            IntPtr session = IntPtr.Zero;
            int len = default(int);
            int result = OpenSDKErrorCode.GENERAL_ERROR;
            try
            {
                result = OpenNetStream.OpenSDK_AllocSessionEx(OpenSDKSession.MessageHandler, userData, ref session, ref len);
            }
            catch (Exception)
            {
                return null;
            }
            if (result != OpenSDKErrorCode.OK)
            {
                //如果分配了会话则释放
                if (session != IntPtr.Zero)
                    CloseAllocion(session);

                return null;
            }

            openSdkSession.Session = session;
            int sessionKey = Marshal.ReadInt32(session);
            SESSIONS[sessionKey] = openSdkSession;
            return openSdkSession;
        }

        //结束会话
        public static int CloseAllocion(IntPtr sessionId)
        {
            try
            {
                return OpenNetStream.OpenSDK_FreeSession(sessionId);
            }
            catch (Exception)
            {

                return OpenSDKErrorCode.GENERAL_ERROR;
            }

        }
        /// <summary>
        /// 关闭资源并结束会话
        /// </summary>
        /// <param name="sessionId"></param>
        /// <returns></returns>
        public static int StopRealPlayAndCloseAllocion(IntPtr sessionId)
        {
            CloseAllocion(sessionId);
            try
            {
                return OpenNetStream.OpenSDK_StopRealPlayEx(sessionId);
            }
            catch (Exception)
            {
                return OpenSDKErrorCode.GENERAL_ERROR;
            }

        }

        /// <summary>
        /// 获取错误码接口
        /// </summary>
        /// <returns>错误码</returns>
        public static int GetLastErrorCode()
        {
            try
            {
                return OpenNetStream.OpenSDK_GetLastErrorCode();
            }
            catch (Exception)
            {

                return OpenSDKErrorCode.GENERAL_ERROR;
            }

        }

        /// <summary>
        /// 获取错误码描述
        /// </summary>
        /// <returns>错误码描述字段</returns>
        public static string GetLastErrorMessage()
        {
            IntPtr result = OpenNetStream.OpenSDK_GetLastErrorDesc();
            if (result != IntPtr.Zero)
                return Marshal.PtrToStringAnsi(result);

            return null;
        }

        /// <summary>
        /// 内存回收
        /// </summary>
        /// <param name="process"></param>
        /// <param name="minSize"></param>
        /// <param name="maxSize"></param>
        /// <returns></returns>
        public static int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize) {
           return OpenNetStream.SetProcessWorkingSetSize(process, minSize, maxSize);
        }

        /// <summary>
        /// 获取设备列表 返回jsonstr
        /// </summary>
        /// <returns></returns>
        public static EZDeviceListReponse GetCameraList(int pageStart = 0, int pageSize = 1000)
        {
            string strBuf = string.Empty;
            IntPtr hBuf = Marshal.StringToHGlobalAnsi(strBuf);
            int iLen = 0;
            int ret = OpenSDKErrorCode.GENERAL_ERROR;
            try
            {
                ret = OpenNetStream.OpenSDK_Data_GetDevListEx(pageStart, pageSize, ref hBuf, ref iLen);
            }
            catch (Exception)
            {

                return null;
            }
            string returnJsonStr = Marshal.PtrToStringAnsi(hBuf);
            EZDeviceListReponse result = null;
            if (ret == OpenSDKErrorCode.OK)
            {
                result = (EZDeviceListReponse)JsonConvert.DeserializeObject(returnJsonStr, typeof(EZDeviceListReponse));
            }
            //Marshal.FreeHGlobal(pBuf); 
            return result;
        }

        /// <summary>
        /// 获取设备详细信息，返回jsonstr
        /// </summary>
        /// <param name="accessToken"></param>
        /// <param name="devSerial"></param>
        /// <returns></returns>
        public static EZDeviceInfoReponse GetDeviceInfo(string accessToken, string devSerial)
        {
            string strBuf = string.Empty;
            IntPtr hBuf = Marshal.StringToHGlobalAnsi(strBuf);
            int iLen = 0;
            int ret = OpenSDKErrorCode.GENERAL_ERROR;
            try
            {
                ret = OpenNetStream.OpenSDK_Data_GetDeviceInfo(accessToken, devSerial, ref hBuf, ref iLen);
            }
            catch (Exception)
            {

                return null;
            }
            string returnJsonStr = Marshal.PtrToStringAnsi(hBuf);
            EZDeviceInfoReponse result = null;
            if (ret == OpenSDKErrorCode.OK)
            {
                result = (EZDeviceInfoReponse)JsonConvert.DeserializeObject(returnJsonStr, typeof(EZDeviceInfoReponse));
            }
            return result;
        }

        /// <summary>
        /// 判断当前摄像头是否在线
        /// </summary>
        /// <param name="accessToken">token值</param>
        /// <param name="devSerial">设备序列号</param>
        /// <returns>监控点在线状态, 0-在线; 非0-离线</returns>
        public static int DevOnline(string accessToken, string devSerial)
        {
            EZDeviceInfoReponse getDeviceInfo = EzvizOpenSDK.GetDeviceInfo(accessToken, devSerial);
            int ret = OpenSDKErrorCode.GENERAL_ERROR;
            if (getDeviceInfo == null)
            {
                return ret;
            }

            List<EZDeviceInfo> _devices = null;
            if (getDeviceInfo.result.Code == (int)EZErrorCode.OK)
            {
                if (getDeviceInfo.result.data == null)
                {
                    ret = OpenSDKErrorCode.GENERAL_ERROR;
                }
                _devices = getDeviceInfo.result.data.ToList();
                foreach (EZDeviceInfo device in _devices)
                {
                    if (device.Online)
                    {
                        ret = OpenSDKErrorCode.OK;

                    }
                    else
                    {
                        ret = OpenSDKErrorCode.GENERAL_ERROR;
                    }
                    break;
                }
            }
            return ret;
        }

        public static string ConvertPlayErrorToMessage(string szError)
        {
            if (szError == "")
            {
                return "";
            }
            string msg;
            if (OpenNetStream.OPEN_SDK_STREAM_ACCESSTOKEN_ERROR_OR_EXPIRE == szError)
            {
                msg = "Accesstoken expire or invalid. update accesstoken.";
            }
            else if (OpenNetStream.OPEN_SDK_STREAM_PU_NO_RESOURCE == szError)
            {
                msg = "Device connection is too many, upgrade the device version, Hikvision devices can consult customer service to obtain the upgrade process.";
            }
            else if (OpenNetStream.OPEN_SDK_STREAM_TRANSF_DEVICE_OFFLINE == szError)
            {
                msg = "Device offline. Connect the device to network and try again.";
            }
            else if (OpenNetStream.OPEN_SDK_STREAM_INNER_TIMEOUT == szError)
            {
                msg = "Request to connect device to timeout, detect device network connection is normal.";
            }
            else if (OpenNetStream.OPEN_SDK_STREAM_INNER_VERIFYCODE_ERROR == szError)
            {
                msg = "Video verificaiton code error, check the verification code marked on the device.";
            }
            else if (OpenNetStream.OPEN_SDK_STREAM_PLAY_FAIL == szError)
            {
                msg = "Failed to play the video, please check the message callback specific error code iErrorCode.";
            }
            else if (OpenNetStream.OPEN_SDK_STREAM_TRANSF_TERMINAL_BINDING == szError)
            {
                msg = "The current account has enabled terminal binding. Only the specified device can log in.";
            }
            else if (OpenNetStream.OPEN_SDK_STREAM_VIDEO_RECORD_NOTEXIST == szError)
            {
                msg = "Video record not found.";
            }
            else if (OpenNetStream.OPEN_SDK_STREAM_VTDU_CONCURRENT_LIMIT == szError)
            {
                msg = "Take the flow of concurrent route restrictions, please upgrade to Enterprise Edition.";
            }
            else if (OpenNetStream.OPEN_SDK_STREAM_UNSUPPORTED == szError)
            {
                msg = "The type of resolution that the device does not support is selected according to the device preview capability level.";
            }
            else
            {
                msg = "Failed to play the video, please check the message callback specific error code iErrorCode.";
            }

            return msg;
        }

        /// <summary>
        /// 将Json转化为对象
        /// </summary>
        /// <typeparam name="TObject"></typeparam>
        /// <param name="json"></param>
        /// <returns></returns>
        private static TObject FromJson<TObject>(string json)
        {
            return JsonConvert.DeserializeObject<TObject>(json);
        }

    }
}